//
//  SPTHandler.m
//  NtoccDriverNew
//
//  Copyright © 2021 NYS. All rights reserved.
//  Created by niyongsheng.github.io on 2021/11/10.

#import "SPTHandler.h"

#define Redundancy          50
#define RedundancySwitch    NO
#define isOpenRemark        YES

@interface SPTHandler () <AMapLocationManagerDelegate>
{
    NSInteger _redundancyLoopCount; // 冗余阈值
}

/// 司机姓名
@property (nonatomic, strong) NSString *driverName;
/// 车辆牌照号
@property (nonatomic, strong) NSString *vehiclePlate;
/// 一车多单备注
@property (nonatomic, strong) NSString *mutableOrderRemark;
/// 定位间隔时间(单位 ms)
@property (nonatomic, assign) NSInteger interval;
/// 上报返回结果
@property (nonatomic, strong) id model;

@property (nonatomic, strong) MapService *mapService;
@property (nonatomic, strong) AMapLocationManager *locationManager;
@end

@implementation SPTHandler
// 循环定时器
static dispatch_source_t _timer;

+ (instancetype)sharedSPTHandler {
    static SPTHandler *sharedSPTHandler = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedSPTHandler = [[self alloc] init];
        [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidFinishLaunchingNotification object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {
            // APP启动
            [UserDefaultUtil saveValue:nil forKey:SPTTimeIntervalKey];
            [KSPTHandler configSPTHandlerWithBranchCode:[UserDefaultUtil valueForKey:LocationBranchCode] completed:^(bool isSuccess, NSInteger code, NSString *msg) {
                [KSPTHandler applicationDidFinishLaunching];
            }];
        }];
        [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillTerminateNotification object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {
            // APP杀死
            [KSPTHandler applicationWillTerminate];
        }];
        // 登录
        [[NSNotificationCenter defaultCenter] addObserverForName:LOGIN_SUCCESS object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {
            [KSPTHandler appWillLogin:note];
        }];
        // 登出
        [[NSNotificationCenter defaultCenter] addObserverForName:LOGIN_LOGOUT object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {
            [KSPTHandler appWillLogout:note];
        }];
    });
    return sharedSPTHandler;
}

- (void)applicationDidFinishLaunching {
    WEAKSELF
    if (!TOKEN_ISEMPTY) {
        // 检查用户信息是否被修改
        [self refreshUserCacheIsUpdateCache:NO completed:^(BOOL isSuccess, BOOL isChangedUserInfo, id response) {
            if (isChangedUserInfo) { // 已修改->初始化->运输中的订单->暂停重启-->(fail:运输中的订单)
                [weakSelf getCurrentOrder:@"[02]App重启 换手机 换人 换车" isRecord:YES isRestart:NO completed:^(bool isSuccess, id model) {
                    [weakSelf updateUserInfoCompleted:^(bool isSuccess) {
                        if (!isSuccess) {
                            [weakSelf getCurrentOrder:@"[02]App重启 换手机 换人 换车" isRecord:YES isRestart:YES completed:nil];
                        }
                    }];
                }];
                
            } else { // 已修改->初始化->运输中的订单
                [weakSelf getCurrentOrder:@"[02]App重启 换手机 换人 换车" isRecord:YES isRestart:YES completed:nil];
            }
        }];
    }
}

- (void)applicationWillTerminate {
    if (self.shippingNoteInfos.count > 0) {
        [self pauseLocationWithRemark:@"[03]App被强制杀死" branchCode:nil isRecord:YES listener:^(id model) {
            
        }];
    }
}

- (void)appWillLogin:(NSNotification *)notifi {
    WEAKSELF
    // 刷新用户信息缓存
    [self refreshUserCacheIsUpdateCache:YES completed:^(BOOL isSuccess, BOOL isChangedUserInfo, id response) {
        if (isSuccess)
            [weakSelf getCurrentOrder:@"[02]登录 换手机 换人 换车" isRecord:YES];
    }];
}

- (void)appWillLogout:(NSNotification *)notifi {
    WEAKSELF
    if (self.shippingNoteInfos.count > 0) {
        NSString *remark = @"[03]换手机 退出登录";
        if ([[notifi object] isKindOfClass:NSString.class]) {
            remark = [notifi object];
        }
        [self pauseLocationWithRemark:remark branchCode:nil isRecord:YES listener:^(id model) {
            [weakSelf cancelAutoSendLocation:YES];
        }];
    } else {
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [weakSelf cancelAutoSendLocation:YES];
        });
    }
}

/// 检查是否开启SDK
- (void)configSPTHandlerWithBranchCode:(NSString*)branchCode {
    [self configSPTHandlerWithBranchCode:branchCode completed:nil];
}
- (void)configSPTHandlerWithBranchCode:(NSString*)branchCode completed:(void(^)(bool isSuccess, NSInteger code, NSString *msg))completed {
    WEAKSELF
    NSMutableDictionary *sptParmas = @{@"branchCode": [UserDefaultUtil valueForKey:LocationBranchCode]}.mutableCopy;
    if ([branchCode isNotBlank])
        [sptParmas setValue:branchCode forKey:@"branchCode"];
    DebugLog(@"初始化SDK2.0 Branch Code:%@", sptParmas);
    
    [HTTPManager getNetworkRequest:CJStringWithFormat(@"%@/partyGroupConfig/getAppSDK", [NSString stringWithFormat:@"%@/ntocc-basic-api",[ReAddressDynamic shared].baseUrl]) withParameter:sptParmas withVC:nil netName:@"省平台开关" success:^(id response, NSString *msg) {
        
        if ([response[@"isReport"] isEqual:@"yes"] && [response[@"iOSAppSecurity"] isNotBlank]) {
            _isReport = YES;
            
            [weakSelf startTimer];
            [weakSelf.locationManager startUpdatingLocation];
            
            [weakSelf locationPermissionCheck:^(bool permit) {
                if (permit) { // 始终允许
                    
                    [KSPTHandler openServiceWithAppId:response[@"iOSAppId"] appSecurity:response[@"iOSAppSecurity"] enterpriseSenderCode:response[@"enterpriseSenderCode"] environment:response[@"environment"] isRecord:YES listener:^(id model) {
                        
                        NSInteger code = [model[@"code"] intValue];
                        if (code == 0) {
                            if (completed) {
                                completed(true, code, @"初始化成功");
                            }
                        } else {
                            if (completed) {
                                completed(false, code, [model stringValueForKey:@"message" default:@""]);
                            }
                        }
                    }];
                }
            }];
            
        } else {
            _isReport = NO;
            if (completed) {
                completed(false, -1, @"省平台配置未开启");
            }
        }
    } failure:^(NSInteger code, NSString *msg) {
        if (completed) {
            completed(false, code, msg);
        }
    }];
}

/// 检查下次上报时间发送位置
- (void)checkInterval {
    NSString *sendTimeStr = [UserDefaultUtil valueForKey:SPTTimeIntervalKey];
    
    if ([sendTimeStr isNotBlank]) {
        NSTimeInterval sendTime = sendTimeStr.integerValue;
        NSTimeInterval currentTime = [[NSDate date] timeIntervalSince1970];
        DebugLog(@"SPT current   time:%f\nSPT next send time:%f", currentTime, sendTime);
        
        if (sendTimeStr && currentTime >= sendTime) {
            // 在下次setInterval之前置空
            [UserDefaultUtil saveValue:@"" forKey:SPTTimeIntervalKey];
            WEAKSELF
            [self sendLocationWithDataArray:self.shippingNoteInfos remark:@"发送位置" isRecord:YES listener:^(id model) {
                
                // 处理上报结果中多出来的订单
                NSArray *dataArr = model[@"data"];
                if ([dataArr isKindOfClass:[NSArray class]] && (dataArr.count > weakSelf.shippingNoteInfos.count)) {
                    NSMutableArray *tempArr = [NSMutableArray array];
                    for (int i = 0; i < weakSelf.shippingNoteInfos.count; i++) {
                        NSString *shippingNoteNumber = [weakSelf.shippingNoteInfos[i] objectForKey:@"shippingNoteNumber"];
                        for (NSDictionary *obj in dataArr) {
                            if ([[obj objectForKey:@"shippingNoteNumber"] isEqual:shippingNoteNumber]) {
                                [tempArr addObject:obj];
                                break;
                            }
                        }
                    }
                    
                    NSMutableArray *resultArr = [[NSMutableArray alloc] initWithArray:dataArr];
                    [resultArr removeObjectsInArray:tempArr];
                    
                    NSMutableArray *codeArr = [NSMutableArray array];
                    for (NSDictionary *obj in resultArr) {
                        [codeArr addObject:[obj objectForKey:@"shippingNoteNumber"]];
                    }
                    [weakSelf getOrderDetailWithCode:[codeArr componentsJoinedByString:@","] stage:SPTStageOther remark:@"运输中订单与上报返回结果不一致"];
                }
            }];
        }
        
    }
    
    // 冗余代码、防止循环定时器停止工作或上报数据异常(关闭)
    if ((_redundancyLoopCount++ > Redundancy) && RedundancySwitch) {
        _redundancyLoopCount = 0;
        [self getCurrentOrder:@"[02]重试" isRecord:NO];
        DebugLog(@"SPT Redundancy times:%ld", _redundancyLoopCount);
    }
}

/// 上报数据字典
static NSDictionary *reportDict(YunDanCenterModel *model) {
    NSDictionary *parmas = @{
        @"shippingNoteNumber" : model.shippingNoteNumber,
        @"serialNumber" : @"0000",
        @"startCountrySubdivisionCode" : model.shipperSubdivisionCode,
        @"endCountrySubdivisionCode" : model.consigneeSubdivisionCode,
        
        @"startLongitude" : model.shipperLongitude,
        @"startLatitude" : model.shipperLatitude,
        @"endLongitude" : model.consigneeLongitude,
        @"endLatitude" : model.consigneeLatitude,
        
        @"startLocationText" : model.shipperAddress,
        @"endLocationText" : model.consigneeAddress,
    };
    return parmas;
}

/// 查询当前订单
- (void)getCurrentOrder:(NSString *)remark isRecord:(BOOL)isRecord {
    [self getCurrentOrder:remark isRecord:isRecord  isRestart:YES completed:nil];
}

- (void)getCurrentOrder:(NSString *)remark isRecord:(BOOL)isRecord isRestart:(BOOL)isRestart completed:(void(^)(bool isSuccess, id model))completed {
    // 信号量数量
    __block NSInteger semaphoreCount = 0;
    WEAKSELF
    [HTTPManager getNetworkRequest:CJStringWithFormat(@"%@%@", [NSString stringWithFormat:@"%@/ntocc-tms-api",[ReAddressDynamic shared].baseUrl], DriverShippingOrder) withParameter:nil withVC:nil netName:@"在运输的订单" success:^(id response, NSString *msg) {
        // 后台装货的异常订单
        NSArray *unstartedShippingOrderArr = [YunDanCenterModel mj_objectArrayWithKeyValuesArray:response[@"startList"]];
        // 后台卸货或删除取消的异常订单
        NSArray *unstopedShippingOrderArr = [YunDanCenterModel mj_objectArrayWithKeyValuesArray:response[@"deletedList"]];
        // 正常运输中的订单
        NSArray *shippingOrderArr = [YunDanCenterModel mj_objectArrayWithKeyValuesArray:response[@"list"]];
        
        // 没有运输中或待运输的订单
        if ((unstartedShippingOrderArr.count + unstopedShippingOrderArr.count + shippingOrderArr.count) == 0) {
            // 停止循环上报
            [weakSelf cancelAutoSendLocation:NO];
        }
        
        // 使用GCD信号量标记多个并行上报任务
        dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
        dispatch_group_t group =  dispatch_group_create();
        // 获取全局并行队列 默认优先级
        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        
        if (unstartedShippingOrderArr.count > 0) {
            NSMutableArray *unstartedArr = [NSMutableArray array];
            
            for (YunDanCenterModel *model in unstartedShippingOrderArr) {
                NSDictionary *parmas = reportDict(model);
                [unstartedArr addObject:parmas];
            }
            
            dispatch_group_async(group, queue, ^{
                semaphoreCount += 1;
                NSString *unstartedBranchCode = [[unstartedShippingOrderArr firstObject] branchCode];
                [weakSelf startLocationWithShippingNoteInfos:unstartedArr remark:@"[00]运单后台装货" branchCode:unstartedBranchCode isRecord:YES listener:^(id model) {
                    dispatch_semaphore_signal(semaphore);
                    
                    if ([model[@"code"] integerValue] == 0) { // 开始成功后，添加到上报数组
                        [weakSelf.shippingNoteInfos addObjectsFromArray:unstartedArr];
                    }
                }];
            });
        }
        
        
        if (unstopedShippingOrderArr.count > 0) {
            NSMutableArray *unstopedArr = [NSMutableArray array];
            
            for (YunDanCenterModel *model in unstopedShippingOrderArr) {
                NSDictionary *parmas = reportDict(model);
                [unstopedArr addObject:parmas];
            }
            
            dispatch_group_async(group, queue, ^{
                semaphoreCount += 1;
                NSString *unstopedBranchCode = [[unstopedShippingOrderArr firstObject] branchCode];
                [KSPTHandler stopLocationWithShippingNoteInfos:unstopedArr remark:@"[01]运单被删除 运单后台卸货" branchCode:unstopedBranchCode isRecord:NO listener:^(id model) {
                    int code = [model[@"code"] intValue];
                    if (code == 0) {
                        // 结束上报完成
                        [KSPTHandler orderReportRecord:model stage:SPTStageStop stageStr:@"stop" dataArray:unstopedArr completed:^(bool isSuccess) {
                            dispatch_semaphore_signal(semaphore);
                        }];
                    } else {
                        // 卸货失败-重试
                        [KSPTHandler reStartLocationWithShippingNoteInfos:unstopedArr remark:@"[02]卸货失败Restart重试" branchCode:unstopedBranchCode isRecord:YES listener:^(id model) {
                            [KSPTHandler stopLocationWithShippingNoteInfos:unstopedArr remark:@"[01]运单被删除 运单后台卸货" branchCode:unstopedBranchCode isRecord:YES listener:^(id model) {
                                dispatch_semaphore_signal(semaphore);
                            }];
                        }];
                    }
                }];
            });
        }
        
        
        if (shippingOrderArr.count > 0) {
            [weakSelf.shippingNoteInfos removeAllObjects];
            
            for (YunDanCenterModel *model in shippingOrderArr) {
                NSDictionary *parmas = reportDict(model);
                [weakSelf.shippingNoteInfos addObject:parmas];
            }
            
            if (isRestart) {
                dispatch_group_async(group, queue, ^{
                    semaphoreCount += 1;
                    // 等待异常订单处理完成，防止send中间点上报到错误的分机构
                    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                        NSString *reStartBranchCode = [[shippingOrderArr firstObject] branchCode];
                        [weakSelf reStartLocationWithShippingNoteInfos:weakSelf.shippingNoteInfos remark:remark branchCode:reStartBranchCode isRecord:isRecord listener:^(id model) {
                            dispatch_semaphore_signal(semaphore);
                        }];
                    });
                });
            }
        }
        
        // 等待并行上报任务全部完成通知回调
        dispatch_group_notify(group, queue, ^{
            for (int i = 0; i < semaphoreCount; i++) {
                dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
            }
            if (completed) {
                completed(false, @"完成");
            }
        });
        
    } failure:^(NSInteger code, NSString *msg) {
        if (completed) {
            completed(false, msg);
        }
    }];
}

///
/// 查询订单详情
/// @param codes 上报单号（多个单号以,分割）
/// @param stage 阶段
/// @param remark 备注
- (void)getOrderDetailWithCode:(NSString *)codes stage:(SPTStage)stage remark:(NSString *)remark {
    if (![codes isNotBlank])
        return;
    
    WEAKSELF
    NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
    [params setValue:codes forKey:@"codes"];
    [HTTPManager getNetworkRequest:CJStringWithFormat(@"%@%@", [NSString stringWithFormat:@"%@/ntocc-tms-api",[ReAddressDynamic shared].baseUrl], OrderDetailByShippingNumber) withParameter:params withVC:nil netName:@"根据上报单号获取运单详情" success:^(id response, NSString *msg) {
        
        NSArray *shippingOrderArr = [YunDanCenterModel mj_objectArrayWithKeyValuesArray:response];
        
        __block BOOL isHasDirtyData = NO;
        for (YunDanCenterModel *model in shippingOrderArr) {
            NSDictionary * shippingNoteInfo = reportDict(model);
            
            id obj = nil;
            switch (stage) {
                case SPTStageStart: {
                    [weakSelf startLocationWithShippingNoteInfos:@[shippingNoteInfo] remark:remark branchCode:model.branchCode isRecord:YES listener:^(id model) {
                        if ([model[@"code"] integerValue] == 0) {
                            [weakSelf.shippingNoteInfos addObject:shippingNoteInfo];
                        }
                    }];
                }
                    break;
                    
                case SPTStageRestart: {
                    [weakSelf reStartLocationWithShippingNoteInfos:@[shippingNoteInfo] remark:remark branchCode:model.branchCode isRecord:YES listener:^(id model) {
                        if ([model[@"code"] integerValue] == 0) {
                            [weakSelf.shippingNoteInfos addObject:shippingNoteInfo];
                        }
                    }];
                }
                    break;
                    
                case SPTStagePause: {
                    for (NSDictionary *shippingDict in self.shippingNoteInfos) {
                        if ([shippingDict[@"shippingNoteNumber"] isEqual:codes]) {
                            obj = shippingDict;
                            break;
                        }
                    }
                    [weakSelf pauseLocationWithShippingNoteInfos:@[shippingNoteInfo] remark:remark branchCode:model.branchCode isRecord:YES listener:^(id model) {
                        if ([model[@"code"] intValue] == 0) {
                            // 移除该上报项
                            obj ? [weakSelf.shippingNoteInfos removeObject:obj] : nil;
                        }
                    }];
                }
                    break;
                    
                case SPTStageStop: {
                    [weakSelf stopLocationWithShippingNoteInfos:@[shippingNoteInfo] remark:remark branchCode:model.branchCode isRecord:YES listener:nil];
                }
                    break;
                    
                case SPTStageOther: { // 订单不一致处理
                    if (model.status >= 3) {
                        // 已卸货的脏数据-标记
                        isHasDirtyData = YES;
                    }
                }
                    break;
                    
                default:
                    break;
            }
            
        }
        
        if (isHasDirtyData) {
            // 清理脏数据
            [weakSelf mapClear];
            // 清理脏数据后重新初始化
            [weakSelf configSPTHandlerWithBranchCode:nil];
        }
        
    } failure:^(NSInteger code, NSString *msg) {
        
    }];
}

- (void)orderReportRecord:(id)model stage:(SPTStage)stage stageStr:(NSString *)stageStr dataArray:(NSArray *)dataArray completed:(void(^)(bool isSuccess))completed {
    [self orderReportRecord:model stage:stage stageStr:stageStr shippingNoteNumber:nil dataArray:dataArray completed:completed];
}
/// 上报记录
/// @param model 上报结果
/// @param stage 阶段
/// @param stageStr 阶段描述
/// @param dataArray 上报数组
/// @param shippingNoteNumber 上报单号（初始化sdk记录使用）
/// @param completed 完成回调
- (void)orderReportRecord:(id)model stage:(SPTStage)stage stageStr:(NSString *)stageStr shippingNoteNumber:(NSString *)shippingNoteNumber dataArray:(NSArray *)dataArray completed:(void(^)(bool isSuccess))completed {
    
    NSMutableDictionary *params = @{
        @"stage": @(stage),
        @"driverName": self.driverName,
        @"licenseNumber": self.vehiclePlate,
        @"branchCode": [UserDefaultUtil valueForKey:LocationBranchCode],
        @"appType": @"IOS",
        @"errorCode": @"",
        @"errorMsg": @"",
    }.mutableCopy;
    
    [params setValue:shippingNoteNumber forKey:@"shippingNoteNumber"];
    
    BOOL isSucess = [model[@"code"] integerValue] == 0;
    if (isSucess) {
        [params setValue:@(0) forKey:@"status"];
        [params setValue:[stageStr stringByAppendingString:[model stringValueForKey:@"message" default:@""]] forKey:@"errorMsg"];
    } else {
        [params setValue:@(1) forKey:@"status"];
        [params setValue:model[@"code"] forKey:@"errorCode"];
        [params setValue:[stageStr stringByAppendingString:[model stringValueForKey:@"message" default:@""]] forKey:@"errorMsg"];
    }
    
    NSMutableArray *paramArr = [NSMutableArray array];
    if (dataArray && dataArray.count > 0) {
        for (NSDictionary *obj in dataArray) {
            NSMutableDictionary *dict = [params deepCopy];
            
            NSString *orderDetailCode = [obj objectForKey:@"shippingNoteNumber"];
            [dict setValue:orderDetailCode forKey:@"shippingNoteNumber"];
            
            if (isSucess) {
                
                NSData *data = [NSJSONSerialization dataWithJSONObject:obj options:kNilOptions error:nil];
                NSString *errStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
                [dict setValue:[stageStr stringByAppendingString:errStr] forKey:@"errorMsg"];
                
            } else {
                
                NSData *data = [NSJSONSerialization dataWithJSONObject:model options:kNilOptions error:nil];
                NSString *errStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
                [dict setValue:[stageStr stringByAppendingString:errStr] forKey:@"errorMsg"];
            }
            
            [paramArr addObject:dict];
        }
    } else {
        [paramArr addObject:params];
    }
    
    [HTTPManager jsonNetworkRequestWithMethod:@"POST" urlString:CJStringWithFormat(@"%@%@", [NSString stringWithFormat:@"%@/ntocc-tms-api",[ReAddressDynamic shared].baseUrl], OrderReportRecord) withParameter:paramArr withVC:nil netName:@"运单SPT上报记录" success:^(id response, NSString *msg) {
        if (completed) {
            completed(true);
        }
        DebugLog(@"SPT/省平台上报记录参数:%@", paramArr);
        DebugLog(@"SPT/省平台上报记录结果:%@", response);
    } failure:^(NSInteger code, NSString *msg) {
        if (completed) {
            completed(false);
        }
    }];
}

/// 上报回调结果
- (void)setModel:(id)model {
    _model = model;
    
    // 判断data数据类型
    if (![model[@"data"] isKindOfClass:[NSArray class]]) return;
    
    // 获取下次上报的最大间隔时间（ms）
    NSNumber *interval = [NSNumber numberWithInt:0];
    NSArray *dataArr = model[@"data"];
    for (NSDictionary *obj in dataArr) {
        NSNumber *orderInterval = [obj objectForKey:@"interval"];
        if ([orderInterval compare:interval] == NSOrderedDescending) {
            interval = orderInterval;
        }
    }
    
    // 缓存
    [self setInterval:interval.integerValue];
}

/// 下次上报间隔时间（ms）
- (void)setInterval:(NSInteger)interval {
    _interval = interval;
    
    // 累加时长并缓存
    interval += SPT_Delay_Time;
    
    NSTimeInterval currentTime = [[NSDate date] timeIntervalSince1970];
    NSTimeInterval nextRepostTime = interval/1000 + currentTime;
    [UserDefaultUtil saveValue:[NSString stringWithFormat:@"%.3f", nextRepostTime] forKey:SPTTimeIntervalKey];
    
    // 开启循环定时触发器
    [self startTimer];
}

// 开启循环定时器
- (void)startTimer {
    if (_timer) return;
    
    WEAKSELF
    NSTimeInterval second = SPT_Time_Interval;
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
    dispatch_source_set_timer(_timer, dispatch_walltime(NULL, 2 * NSEC_PER_SEC), second * NSEC_PER_SEC, 0);
    // 定时器触发事件
    dispatch_source_set_event_handler(_timer, ^{
        dispatch_async(dispatch_get_main_queue(), ^{
            DebugLog(@"SPT/省平台 触发器 %ld", _interval);
            [weakSelf checkInterval];
        });
    });
    
    dispatch_resume(_timer);
}

/// 停止自动上报
- (void)cancelAutoSendLocation:(BOOL)isClearCache {
    // 关闭定时器
    if (_timer) {
        dispatch_source_cancel(_timer);
        _timer = nil;
    }
    [self.locationManager stopUpdatingLocation];
    
    if (isClearCache) {
        [self.shippingNoteInfos removeAllObjects];
        [UserDefaultUtil removeForKey:SPT_NAME];
        [UserDefaultUtil removeForKey:SPT_PLATE];
    }
}

/// 缓存处理方法
static BOOL userInfoCacheHandler(id response, BOOL isUpdateCache) {
    NSString *plate = @"";
    NSString *name = @"";
    BOOL isChangedUserInfo = NO;
    
    if (![DCSpeedy isBlankString:response[@"vehicleLicense"]]) {
        plate = response[@"vehicleLicense"];
    }
    if (![DCSpeedy isBlankString:response[@"name"]]) {
        name = response[@"name"];
    }
    
    if (!([plate isEqualToString:[UserDefaultUtil valueForKey:SPT_PLATE]] && [name isEqualToString:[UserDefaultUtil valueForKey:SPT_NAME]])) {
        isChangedUserInfo = YES;
    }
    
    if (isUpdateCache) {
        [UserDefaultUtil saveValue:plate forKey:SPT_PLATE];
        [UserDefaultUtil saveValue:name forKey:SPT_NAME];
    }
    
    return isChangedUserInfo;
}

/// 更新用户信息信息
- (void)updateUserInfo {
    [self updateUserInfoCompleted:nil];
}
- (void)updateUserInfoCompleted:(void(^)(bool isSuccess))completed {
    
    WEAKSELF
    DebugLog(@"未修改的司机信息：%@%@", self.driverName, self.vehiclePlate);
    [self pauseLocationWithRemark:@"[03]换车 换人" branchCode:nil isRecord:YES listener:^(id model) {
        
        [HTTPManager getNetworkRequest:CJStringWithFormat(@"%@%@", [NSString stringWithFormat:@"%@/ntocc-basic-api",[ReAddressDynamic shared].baseUrl], PERSONALCENTER_INDEX) withParameter:@{@"token":[UserDefaultUtil valueForKey:USER_TOKEN]} withVC:nil netName:@"个人中心初始化" success:^(id response, NSString *msg) {
            if (Identity_CarCaptain == NO) { // SPT缓存车牌号、司机姓名
                
                userInfoCacheHandler(response, YES);
                DebugLog(@"已修改的司机信息：%@%@", self.driverName, self.vehiclePlate);
                
                dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                    [weakSelf reStartLocationWithRemark:@"[02]换车 换人" branchCode:nil isRecord:YES listener:^(id model) {
                        if (completed) {
                            completed(true);
                        }
                    }];
                });
                
            } else {
                if (completed) {
                    completed(false);
                }
            }
        } failure:^(NSInteger code, NSString *msg) {
            if (completed) {
                completed(false);
            }
        }];
        
    }];
}

- (void)refreshUserCacheIsUpdateCache:(BOOL)isUpdateCache completed:(void(^)(BOOL isSuccess, BOOL isChangedUserInfo, id response))completed {
    
    [HTTPManager getNetworkRequest:CJStringWithFormat(@"%@%@", [NSString stringWithFormat:@"%@/ntocc-basic-api",[ReAddressDynamic shared].baseUrl], PERSONALCENTER_INDEX) withParameter:@{@"token":[UserDefaultUtil valueForKey:USER_TOKEN]} withVC:nil netName:@"刷新个人信息缓存" success:^(id response, NSString *msg) {
        
        [UserDefaultUtil saveValue:response forKey:Login_Branch];
        [UserDefaultUtil saveValue:response[@"branchCode"] forKey:BranchCode];
        
        if (Identity_CarCaptain == NO) { // SPT缓存车牌号、司机姓名
            
            BOOL isChangedUserInfo = userInfoCacheHandler(response, isUpdateCache);
            
            completed ? completed(YES, isChangedUserInfo, response) : nil;
        } else {
            completed ? completed(NO, NO, response) : nil;
        }
    } failure:^(NSInteger code, NSString *msg) {
        
        completed ? completed(NO, NO, msg) : nil;
    }];
}

- (NSString *)mutableOrderRemarkHandel:(NSArray *)array remark:(NSString *)remark {
    if (array.count > 1) {
        return [remark stringByAppendingString:self.mutableOrderRemark];
    } else {
        return remark;
    }
}

/// 测试省平台环境
- (void)testSpt {
    if (SPTIsParams) {
        NSString *environment = SPTIsRelease ? @"release" : @"debug";
        NSString *appId = APP_BUNDLEID;
        
        if ([SPTAppId isNotBlank])
            appId = SPTAppId;
        
        [self.mapService openServiceWithAppId:appId
                                  appSecurity:SPTAppSecurity
                         enterpriseSenderCode:SPTEnterpriseSenderCode
                                  environment:environment
                                     listener:^(id  _Nonnull model) {
            DebugLog(@"省平台%@配置参数初始化结果:%@", environment, model);
        }];
        
    } else {
        [self configSPTHandlerWithBranchCode:nil completed:^(bool isSuccess, NSInteger code, NSString *msg) {
            DebugLog(@"省平台配置参数初始化结果:%@", msg);
        }];
    }
}

#pragma mark - 上报服务
/// 初始化SDK
- (void)openServiceWithAppId:(NSString *)appId appSecurity:(NSString *)appSecurity enterpriseSenderCode:(NSString *)enterpriseSenderCode environment:(NSString *)environment isRecord:(BOOL)isRecord listener:(void(^)(id model))listener {
    NSParameterAssert(appSecurity && enterpriseSenderCode && environment);
    WEAKSELF
    [weakSelf.mapService openServiceWithAppId:appId
                                  appSecurity:appSecurity
                         enterpriseSenderCode:enterpriseSenderCode
                                  environment:environment
                                     listener:^(id  _Nonnull model) {
        DebugLog(@"SPT/省平台 初始化%@", model);
        // 上报记录
        NSString *shippingNoteNumber = @"";
        if (weakSelf.shippingNoteInfos.count > 0) {
            shippingNoteNumber = [[weakSelf.shippingNoteInfos lastObject] objectForKey:@"shippingNoteNumber"];
            if (isRecord && [model[@"code"] intValue] != 0) {
                [weakSelf orderReportRecord:model stage:SPTStageAuth stageStr:@"auth开启服务" shippingNoteNumber:shippingNoteNumber dataArray:nil completed:nil];
            }
        }
        if (listener) {
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                // 防止888888未初始化错误
                listener(model);
            });
        }
    }];
}

/// 开始
- (void)startLocationWithRemark:(NSString*)remark branchCode:(NSString*)branchCode isRecord:(BOOL)isRecord listener:(void(^)(id model))listener {
    [self startLocationWithShippingNoteInfos:self.shippingNoteInfos remark:remark branchCode:branchCode isRecord:isRecord listener:listener];
}
- (void)startLocationWithShippingNoteInfos:(NSArray *)shippingNoteInfos remark:(NSString*)remark branchCode:(NSString*)branchCode isRecord:(BOOL)isRecord listener:(void(^)(id model))listener {
    WEAKSELF
    if ([branchCode isNotBlank]) {
        [self configSPTHandlerWithBranchCode:branchCode completed:^(bool isSuccess, NSInteger code, NSString *msg) {
            [weakSelf startMethod:isRecord listener:listener remark:remark shippingNoteInfos:shippingNoteInfos];
        }];
    } else {
        [self startMethod:isRecord listener:listener remark:remark shippingNoteInfos:shippingNoteInfos];
    }
}
/// 开始上报
- (void)startMethod:(BOOL)isRecord listener:(void (^)(id))listener remark:(NSString *)remark shippingNoteInfos:(NSArray *)shippingNoteInfos {
    WEAKSELF
    [self.mapService startLocationWithShippingNoteInfos:shippingNoteInfos
                                             driverNameView:self.driverName
                                          vehicleNumberView:self.vehiclePlate
                                                     remark:isOpenRemark ? [self mutableOrderRemarkHandel:shippingNoteInfos remark:remark] : @""
                                                   listener:^(id  _Nonnull model) {
        DebugLog(@"SPT/省平台 开始%@", model);
        [weakSelf setModel:model];
        // 上报记录
        if (isRecord) {
            [weakSelf orderReportRecord:model stage:SPTStageStart stageStr:[@"start开始" stringByAppendingString:[self mutableOrderRemarkHandel:shippingNoteInfos remark:remark]] dataArray:shippingNoteInfos completed:nil];
        }
        
        if (listener) {
            listener(model);
        }
    }];
}

/// 发送
- (void)sendLocationWithDataArray:(NSMutableArray *)dataArray remark:(NSString*)remark isRecord:(BOOL)isRecord listener:(void(^)(id model))listener {
    if (![dataArray isKindOfClass:[NSArray class]]) return;
    
    WEAKSELF
    [weakSelf.mapService sendLocationWithShippingNoteInfos:dataArray
                                            driverNameView:self.driverName
                                         vehicleNumberView:self.vehiclePlate
                                                    remark:isOpenRemark ? [self mutableOrderRemarkHandel:dataArray remark:remark] : @""
                                                  listener:^(id  _Nonnull model) {
        DebugLog(@"SPT/省平台 发送位置%@", model);
        
        if ([model[@"code"] intValue] != 0) {
            [weakSelf getCurrentOrder:@"[02]发送轨迹点失败，重新开始" isRecord:YES];
        }
        
        // 记录时间
        [weakSelf setModel:model];
        
        // 上报记录
        if (isRecord) {
            [weakSelf orderReportRecord:model stage:SPTStageSend stageStr:[@"send上传定位" stringByAppendingString:[self mutableOrderRemarkHandel:dataArray remark:remark]] dataArray:dataArray completed:nil];
        }
        
        if (listener) {
            listener(model);
        }
    }];
}

/// 暂停
- (void)pauseLocationWithRemark:(NSString*)remark branchCode:(NSString*)branchCode isRecord:(BOOL)isRecord listener:(void(^)(id model))listener {
    [self pauseLocationWithShippingNoteInfos:self.shippingNoteInfos remark:remark branchCode:branchCode isRecord:isRecord listener:listener];
}
- (void)pauseLocationWithShippingNoteInfos:(NSArray *)shippingNoteInfos remark:(NSString*)remark branchCode:(NSString*)branchCode isRecord:(BOOL)isRecord listener:(void(^)(id model))listener {
    WEAKSELF
    if ([branchCode isNotBlank]) {
        [self configSPTHandlerWithBranchCode:branchCode completed:^(bool isSuccess, NSInteger code, NSString *msg) {
            [weakSelf pauseMethod:isRecord listener:listener remark:remark shippingNoteInfos:shippingNoteInfos];
        }];
    } else {
        [self pauseMethod:isRecord listener:listener remark:remark shippingNoteInfos:shippingNoteInfos];
    }
}
/// 暂停上报
- (void)pauseMethod:(BOOL)isRecord listener:(void (^)(id))listener remark:(NSString *)remark shippingNoteInfos:(NSArray *)shippingNoteInfos {
    WEAKSELF
    [self.mapService pauseLocationWithShippingNoteInfos:shippingNoteInfos
                                             driverNameView:self.driverName
                                          vehicleNumberView:self.vehiclePlate
                                                     remark:isOpenRemark ? [self mutableOrderRemarkHandel:shippingNoteInfos remark:remark] : @""
                                                   listener:^(id  _Nonnull model) {
        DebugLog(@"SPT/省平台 暂停%@", model);
        // 上报记录
        if (isRecord) {
            [weakSelf orderReportRecord:model stage:SPTStagePause stageStr:[@"pause暂停" stringByAppendingString:[self mutableOrderRemarkHandel:shippingNoteInfos remark:remark]] dataArray:shippingNoteInfos completed:nil];
        }
        if (listener) {
            listener(model);
        }
    }];
}

/// 恢复
- (void)reStartLocationWithRemark:(NSString*)remark branchCode:(NSString*)branchCode isRecord:(BOOL)isRecord listener:(void(^)(id model))listener {
    [self reStartLocationWithShippingNoteInfos:self.shippingNoteInfos remark:remark branchCode:branchCode isRecord:isRecord listener:listener];
}
- (void)reStartLocationWithShippingNoteInfos:(NSArray *)shippingNoteInfos remark:(NSString*)remark branchCode:(NSString*)branchCode isRecord:(BOOL)isRecord listener:(void(^)(id model))listener {
    WEAKSELF
    if ([branchCode isNotBlank]) {
        [self configSPTHandlerWithBranchCode:branchCode completed:^(bool isSuccess, NSInteger code, NSString *msg) {
            [weakSelf reStartMethod:isRecord listener:listener remark:remark shippingNoteInfos:shippingNoteInfos];
        }];
    } else {
        [self reStartMethod:isRecord listener:listener remark:remark shippingNoteInfos:shippingNoteInfos];
    }
}
/// 恢复上报
- (void)reStartMethod:(BOOL)isRecord listener:(void (^)(id))listener remark:(NSString *)remark shippingNoteInfos:(NSArray *)shippingNoteInfos {
    WEAKSELF
    [self.mapService reStartLocationWithShippingNoteInfos:shippingNoteInfos
                                               driverNameView:self.driverName
                                            vehicleNumberView:self.vehiclePlate
                                                       remark:isOpenRemark ? [self mutableOrderRemarkHandel:shippingNoteInfos remark:remark] : @""
                                                     listener:^(id  _Nonnull model) {
        DebugLog(@"SPT/省平台 恢复%@", model);
        [weakSelf setModel:model];
        // 上报记录
        if (isRecord) {
            [weakSelf orderReportRecord:model stage:SPTStageRestart stageStr:[@"reStart重启" stringByAppendingString:[self mutableOrderRemarkHandel:shippingNoteInfos remark:remark]] dataArray:shippingNoteInfos completed:nil];
        }
        if (listener) {
            listener(model);
        }
    }];
}

/// 结束
- (void)stopLocationWithRemark:(NSString*)remark branchCode:(NSString*)branchCode isRecord:(BOOL)isRecord listener:(void(^)(id model))listener {
    [self stopLocationWithShippingNoteInfos:self.shippingNoteInfos remark:remark branchCode:branchCode isRecord:isRecord listener:listener];
}
- (void)stopLocationWithShippingNoteInfos:(NSArray *)shippingNoteInfos remark:(NSString*)remark branchCode:(NSString*)branchCode isRecord:(BOOL)isRecord listener:(void(^)(id model))listener {
    WEAKSELF
    if ([branchCode isNotBlank]) {
        [self configSPTHandlerWithBranchCode:branchCode completed:^(bool isSuccess, NSInteger code, NSString *msg) {
            [weakSelf stopMethod:isRecord listener:listener remark:remark shippingNoteInfos:shippingNoteInfos];
        }];
    } else {
        [self stopMethod:isRecord listener:listener remark:remark shippingNoteInfos:shippingNoteInfos];
    }
}
/// 结束上报
- (void)stopMethod:(BOOL)isRecord listener:(void (^)(id))listener remark:(NSString *)remark shippingNoteInfos:(NSArray *)shippingNoteInfos {
    WEAKSELF
    [self.mapService stopLocationWithShippingNoteInfos:shippingNoteInfos
                                            driverNameView:self.driverName
                                         vehicleNumberView:self.vehiclePlate
                                                    remark:isOpenRemark ? [self mutableOrderRemarkHandel:shippingNoteInfos remark:remark] : @""
                                                  listener:^(id  _Nonnull model) {
        DebugLog(@"SPT/省平台 结束%@", model);
        // 成功卸货后从上报数据中移除
        if ([model[@"code"] intValue] == 0) {
            if (shippingNoteInfos.count > 1) {
                [weakSelf.shippingNoteInfos removeObjectsInArray:shippingNoteInfos];
                
            } else {
                id obj = nil;
                NSString *code = [[shippingNoteInfos firstObject] objectForKey:@"shippingNoteNumber"];
                for (NSDictionary *shippingDict in weakSelf.shippingNoteInfos) {
                    if ([shippingDict[@"shippingNoteNumber"] isEqual:code]) {
                        obj = shippingDict;
                        break;
                    }
                }
                obj ? [weakSelf.shippingNoteInfos removeObject:obj] : nil;
            }
        }
        // 上报记录
        if (isRecord) {
            [weakSelf orderReportRecord:model stage:SPTStageStop stageStr:[@"stop停止" stringByAppendingString:[self mutableOrderRemarkHandel:shippingNoteInfos remark:remark]] dataArray:shippingNoteInfos completed:nil];
        }
        if (listener) {
            listener(model);
        }
    }];
}

/// 清空SDK缓存
- (void)mapClear {
    @try {
        // KVC清空SDK本地缓存，防止出现脏数据
        [self.mapService valueForKey:@"clearLocalStorage"];
    } @catch (NSException *exception) {
        DebugLog(@"清空SDK本地上报缓存异常：%@", exception.description);
    }
}

#pragma mark - getter
- (NSMutableArray *)shippingNoteInfos {
    if (!_shippingNoteInfos) {
        _shippingNoteInfos = [[NSMutableArray alloc] init];
    }
    return _shippingNoteInfos;
}

- (NSString *)driverName {
    return [UserDefaultUtil valueForKey:SPT_NAME];;
}

- (NSString *)vehiclePlate {
    return [UserDefaultUtil valueForKey:SPT_PLATE];
}

- (NSString *)mutableOrderRemark {
    return [@" [99]" stringByAppendingString:self.vehiclePlate];
}

- (CLLocation *)location {
    if (!_location) {
        _location = [[CLLocation alloc] initWithLatitude:0.0 longitude:0.0];
    }
    return _location;
}

- (MapService *)mapService {
    if (!_mapService) {
        _mapService = [[MapService alloc] init];
    }
    return _mapService;
}

- (AMapLocationManager *)locationManager {
    if (!_locationManager) {
        _locationManager = [[AMapLocationManager alloc] init];
        [_locationManager setDelegate:self];
        // 设置期望定位精度
        [_locationManager setDesiredAccuracy:kCLLocationAccuracyHundredMeters];
        // 设置定位超时时间
        [_locationManager setLocationTimeout:DefaultLocationTimeout];
        [self.locationManager setLocatingWithReGeocode:YES];
    }
    return _locationManager;
}

#pragma mark - AMapLocationManager Delegate
- (void)amapLocationManager:(AMapLocationManager *)manager didUpdateLocation:(CLLocation *)location reGeocode:(AMapLocationReGeocode *)reGeocode {
    self.location = location;
    if (reGeocode) {
        self.address = reGeocode.formattedAddress;
    } else {
        self.address = @"";
    }
    [self checkInterval];
}

#pragma mark - 始终定位权限检查
- (void)locationPermissionCheck:(void(^)(bool permit))completed {
    if ([CLLocationManager locationServicesEnabled] && ([CLLocationManager authorizationStatus] != kCLAuthorizationStatusAuthorizedAlways)) {
        UIAlertController *alertView = [UIAlertController alertControllerWithTitle:@"⚠️警告⚠️" message: CJStringWithFormat(@"请到设置->隐私->定位服务->【%@】切换到“始终“，否则将无法完成省平台轨迹上报。", APP_NAME) preferredStyle:UIAlertControllerStyleAlert];
        UIAlertAction *sureAction = [UIAlertAction actionWithTitle:@"前往设置" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
            [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString] options:@{} completionHandler:nil];
        }];
        UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil];
        [alertView addAction:sureAction];
        [alertView addAction:cancelAction];
        
        [[UIApplication sharedApplication].delegate.window.rootViewController presentViewController:alertView animated:YES completion:nil];
        completed(false);
    } else {
        completed(true);
    }
}
@end
